hhkb
컴퓨터과학

어셈블리_08_레지스터 조작을 통한 실행 흐름 제어

작성자 : Heehyeon Yoo|2025-10-16
# Assembly# GDB# Register Patch# Control Flow

디버거를 사용하면 실행 중인 프로그램의 메모리나 레지스터 값을 임의로 변경할 수 있다. 이를 런타임 패치(Runtime Patch)라 하며, 인증 로직 우회나 취약점 검증에 활용된다.

1. 값 변경: set 명령어

GDB의 set 명령어로 레지스터 값을 즉시 수정할 수 있다.

set $레지스터 = 값

2. 실행 흐름 조작(RIP)

RIP 레지스터는 다음에 실행할 명령어의 주소를 담고 있다. 이 값을 변경하면 프로그램의 실행 흐름을 강제로 이동시킬 수 있다.

(gdb) set $rip = 0x401234

예를 들어 로그인 실패 루틴으로 진입하기 직전, RIP를 성공 루틴의 주소로 덮어쓰면 인증을 우회할 수 있다. 단, 스택 프레임 상태가 맞지 않을 경우 프로그램이 비정상 종료(Crash)될 수 있다.

3. 조건 분기 조작(EFLAGS)

대부분의 분기문(JE, JNE 등)은 플래그 레지스터(RFLAGS) 상태를 참조한다.

test rax, rax   ; rax가 0인지 확인
jz fail         ; 0이면(ZF=1) fail로 점프

위 상황에서 fail로 분기해야 할 경우라도, GDB에서 강제로 ZF 플래그를 0으로 설정하면 점프하지 않고 다음 코드를 실행한다.

; ZF(Zero Flag) 비트를 강제 해제
set $eflags &= ~(1 << 6)

이러한 런타임 패치는 메모리 상에서만 유효하며, 영구적인 수정을 위해서는 바이너리 파일 자체를 패치해야 한다.

NOP (No Operation) 패치
흐름을 바꾸는 것이 아니라, 특정 명령어를 아예 없던 일로 만들고 싶을 때는 해당 명령어의 기계어 코드를 0x90 (NOP)으로 덮어쓴다. 이를 통해 인증 확인 함수 호출(CALL) 자체를 지워버리는 등의 과격한 패치가 가능하다. 이 기법을 NOP Sled라고도 부른다.